﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YasharEl.Infrastructure.EntityModel;
using YasharEl.Infrastructure.EntityModel.Specifications;
using System.Linq.Expressions;
using System.Diagnostics.Contracts;

namespace YasharEl.Infrastructure.PersistenceModel
{
    [ContractClass(typeof(GenericReadOnlyRepositoryContract<,>))]
    public interface IGenericReadOnlyRepository<TEntity, TIdentity> where TEntity : class, IReadOnlyEntity<TIdentity>
    {
        /// <summary>
        /// Gets entity from the storage by it's Id.
        /// </summary>
        TEntity GetById(TIdentity id);

        /// <summary>
        /// Gets all entities of the type from the storage. 
        /// </summary>
        IList<TEntity> GetAll();

        /// <summary>
        /// Gets specification interface for complex searching for an entity or entities.
        /// </summary>
        /// <typeparam name="TSpecification">Concrete specification that will be resolved
        /// and initialized with underlying unit of work instance. This ensures fluent 
        /// and strongly typed way of connecting repository (uow) and specifications.</typeparam>
        TSpecification Specify<TSpecification>() where TSpecification : ISpecification<TEntity, TIdentity>;

        IEnumerable<TEntity> Query(Expression<Func<TEntity, bool>> filter);
    }

    [ContractClassFor(typeof(IGenericReadOnlyRepository<,>))]
    internal abstract class GenericReadOnlyRepositoryContract<TEntity, TIdentity> : IGenericReadOnlyRepository<TEntity, TIdentity>
        where TEntity : class, IReadOnlyEntity<TIdentity>
    {
        #region IGenericReadOnlyRepository<TEntity,TIdentity> Members

        public TEntity GetById(TIdentity id)
        {
            return default(TEntity);
        }

        public IList<TEntity> GetAll()
        {
            return new List<TEntity>();
        }

        public TSpecification Specify<TSpecification>() where TSpecification : ISpecification<TEntity, TIdentity>
        {
            return default(TSpecification);
        }

        public IEnumerable<TEntity> Query(Expression<Func<TEntity, bool>> filter)
        {
            return new List<TEntity>();
        }

        #endregion
    }
}
